package middleware

import (
	"bytes"
	"fmt"
	"github.com/zeromicro/go-zero/core/logx"
	"insighttracking/common/utils"
	"io"
	"log"
	"net/http"
	"strings"
)

type LoggerMiddleWare struct {
	// 可以在这里添加操作数据的依赖
}

func NewLoggerMiddleWare() *LoggerMiddleWare {
	return &LoggerMiddleWare{}
}

type logResponseWriter struct {
	writer http.ResponseWriter
	code   int
	// 存响应数据
	buf *bytes.Buffer
}

func newLogResponseWriter(writer http.ResponseWriter, code int) *logResponseWriter {
	var buf bytes.Buffer
	return &logResponseWriter{
		writer: writer,
		code:   code,
		buf:    &buf,
	}
}

func (w *logResponseWriter) Write(bs []byte) (int, error) {
	w.buf.Write(bs)
	return w.writer.Write(bs)
}

func (w *logResponseWriter) Header() http.Header {
	return w.writer.Header()
}

func (w *logResponseWriter) WriteHeader(code int) {
	w.code = code
	w.writer.WriteHeader(code)
}

func (m *LoggerMiddleWare) Handle(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var dup io.ReadCloser
		dup, r.Body, _ = drainBody(r.Body)
		lwr := newLogResponseWriter(w, http.StatusOK)
		next(lwr, r)
		r.Body = dup
		// 将自己逻辑写在logDetailLogic
		m.logDetailLogic(r, lwr)
	}
}

func (m *LoggerMiddleWare) logDetailLogic(request *http.Request, response *logResponseWriter) {
	//请求方式
	method := request.Method
	//请求路由
	reqUrl := request.RequestURI
	//请求路由
	reqUrlList := strings.Split(request.URL.String(), "?")
	//bs, _ := io.ReadAll(request.Body)
	var bs = ""
	clientIP := utils.ClientIP(request)
	if method == http.MethodPost && request.Body != nil {
		bs1, _ := io.ReadAll(request.Body)
		bs = string(bs1)
		//log.Println("请求内容：", string(bs))
	}
	log.Println("请求参数:", reqUrlList, bs)
	loggerStr := fmt.Sprintf("请求参数:来源IP地址:%s,请求地址:【%s】%s,当前请求参数:%v,url上的参数为:%v", clientIP, method, reqUrl, bs, reqUrlList)
	logx.Info(loggerStr)
	if len(response.buf.Bytes()) > 0 {
		//log.Println("响应内容:", response.buf.String())
		logx.Info("请求响应:", response.buf.String())
	}
}

// drainBody from httputil.drainBody
func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) {
	if b == nil || b == http.NoBody {
		// No copying needed. Preserve the magic sentinel meaning of NoBody.
		return http.NoBody, http.NoBody, nil
	}
	var buf bytes.Buffer
	if _, err = buf.ReadFrom(b); err != nil {
		return nil, b, err
	}
	if err = b.Close(); err != nil {
		return nil, b, err
	}
	return io.NopCloser(&buf), io.NopCloser(bytes.NewReader(buf.Bytes())), nil
}
